use serde::{Deserialize, Serialize};
use serde_json::Value;
use crate::protocol::type_schema::TypeSchema;
use std::fmt;

pub type NominalTask = String;

#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
pub struct TaskSignature {
    pub name: String,
    pub input_type: String,
    pub output_type: String,
}

/* 
    规则：
    1. 任务名 ':' 输入类型 '->' 输出类型
    2. `:`和`->`只出现一次，且必须出现
    3. 输入类型和输出类型解析到TypeSchema类，都是递归定义的
    4. 空格会被忽略

    (1) task1: Void -> List<String> 
    (2) task2: String -> Dict<String, Pose> // here `Pose` is a DataType of this system
    (3) task3: (String, Project) -> List<(DeepModel, Dict<String, Json>)> // `Project` and `DeepModel` are both DataTypes of this system

    we should parse them into:
    (1) name: "task1", inout_type: (TypeSchema::Void, TypeSchema::List(TypeSchema::Str))
    (2) name: "task2", inout_type: (TypeSchema::Str, TypeSchema::Dict(TypeSchema::Str, TypeSchema::DataType("Pose")))
    (3) name: "task3", inout_type: (TypeSchema::Tuple(vec![TypeSchema::Str, TypeSchema::DataType("Project")]), TypeSchema::List(TypeSchema::Tuple(vec![TypeSchema::DataType("DeepModel"), TypeSchema::Dict(TypeSchema::Str, TypeSchema::Json)])))
*/
#[derive(Debug, PartialEq, Clone)]
pub struct SymbolicTask {
    pub name: String,
    pub input_type: TypeSchema,
    pub output_type: TypeSchema,
}

impl SymbolicTask {
    pub fn new(name: String, input_type: TypeSchema, output_type: TypeSchema) -> Self {
        Self { name, input_type, output_type }
    }
    pub fn short_str(&self) -> String {
        format!("{}: {} -> {}", self.name, self.input_type.short_str(), self.output_type.short_str())
    }
    pub fn short_sig(&self) -> TaskSignature {
        TaskSignature { name: self.name.clone(), input_type: self.input_type.short_str(), output_type: self.output_type.short_str() }
    }
}

impl fmt::Display for SymbolicTask {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}: {} -> {}", self.name, self.input_type, self.output_type)
    }
}

#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
pub enum TaskStatus {
    Created,
    Running,
    Completed,
    Failed,
    Stopped,
    Closed,
    ResultReceived,
    FailedToGetResult
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TaskProgressD {
    pub status: TaskStatus,
    pub percentage: f64,
    pub errmsg: Option<String>
}

#[derive(Debug, Serialize, Deserialize)]
pub struct TaskInitD {
    pub task_id: String,
    pub progress_pipe_addr: String,
    pub log_pipe_addr: Option<String>,
    pub result_addr: String,
    pub instant_result: Option<Value>,
    pub status: Option<TaskStatus>,
    pub error_message: Option<String>
}